package com.zc.manager.device.domain;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.annotation.Excel.Type;
import com.ruoyi.common.annotation.Excels;
import com.ruoyi.common.core.domain.BaseEntity;
import com.zc.core.ProtocolStandbyValue;
import com.zc.core.device.DeviceConfigKey;
import com.zc.core.device.ProductInfo;
import lombok.Data;
import org.hibernate.validator.constraints.Range;

import com.zc.core.message.codec.Transport;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;

import static com.zc.manager.device.enums.DeviceType.gateway;

/**
 * 产品对象 athena_iot_product
 *
 * @author xiepufeng
 * @date 2022-05-31
 */
@Data
public class IotProduct extends BaseEntity
{
    private static final long serialVersionUID = 1L;

    /** 已发布状态 */
    public static final byte PUBLISH = 1;

    /** 未发布状态 */
    public static final byte UN_PUBLISH = 0;

    public static final String GATEWAY = "gateway";
    public static final String DEVICE = "device";
    public static final String CHILDREN_DEVICE = "childrenDevice";

    /** 产品ID */
    @Excel(name = "产品ID")
    @NotBlank(message = "产品ID不能为空")
    @Size(max = 50, message = "产品ID长度不能超过50个字符")
    private String id;

    /** 产品名称 */
    @Excel(name = "产品名称")
    @NotBlank(message = "产品名称不能为空")
    @Size(max = 50, message = "产品名称长度不能超过50个字符")
    private String productName;

    /** 所属品类 */
    @Excel(name = "所属品类", type = Type.IMPORT)
    @NotNull(message = "所属品类不能为空")
    private Long categoryId;

    /** 品类对象 */
    @Excels({
            @Excel(name = "品类名称", targetAttr = "categoryName", type = Type.EXPORT),
            @Excel(name = "品类标识", targetAttr = "categoryMark", type = Type.EXPORT)
    })
    private IotCategory category;

    /** 消息协议 */
    @Excel(name = "消息协议")
    @NotNull(message = "消息协议不能为空")
    private String protocolId;

    /** 协议对象 */
    @Excels({
            @Excel(name = "协议名称", targetAttr = "protocolName", type = Type.EXPORT)
    })
    private IotProtocol protocol;

    /** 发布状态 */
    @Excel(name = "发布状态", readConverterExp = "0=未发布,1=已发布")
    @NotNull(message = "发布状态不能为空")
    @Range(min = 0, max = 1, message = "发布状态只能是0或1")
    private Byte publishState;

    /** 传输协议 */
    @Excel(name = "传输协议")
    @NotBlank(message = "传输协议不能为空")
    private String transportProtocol;

    /** 存储策略 */
    @Excel(name = "存储策略", readConverterExp = "none=不存储,default-column=默认-列式存储,default-row=默认-行式存储")
    @NotBlank(message = "存储策略不能为空")
    @Pattern(regexp = "none|default-column|default-row", message = "无效的设备类型")
    private String storePolicy;

    /** 物模型 */
    @Excel(name = "物模型")
    private String metadata;

    /** 其他配置 */
    private String configuration;

    /** 协议支持 */
    private String protocolStandby;

    /** 设备类型 */
    @Excel(name = "设备类型")
    @Pattern(regexp = "gateway|device|childrenDevice", message = "无效的设备类型")
    @NotNull(message = "设备类型不能为空")
    private String deviceType;

    /** 图标地址 */
    @Excel(name = "图标地址")
    private String photoUrl;

    /** 产品描述 */
    @Excel(name = "产品描述")
    @Size(max = 200, message = "产品描述长度不能超过200个字符")
    private String description;

    /**
     * 数据存储策略配置 todo
     */
    private Map<String, Object> storePolicyConfiguration;

    public Optional<Transport> getTransportEnum(Collection<? extends Transport> candidates) {
        for (Transport transport : candidates) {
            if (transport.isSame(transportProtocol)) {
                return Optional.of(transport);
            }
        }
        return Optional.empty();
    }

    public ProductInfo toProductInfo() {
        return ProductInfo
                .builder()
                .id(getId()) // 产品ID
                .protocol(getProtocolId()) // 协议ID
                .metadata(getMetadata()) // 元数据
                .protocolStandby(IotProduct.toProtocolStandbyValue(protocolStandby))
                .build()
                .addConfig(DeviceConfigKey.isGatewayDevice, gateway.getValue().equals(getDeviceType()))
                .addConfig("storePolicy", storePolicy) // 存储策略
                .addConfig("storePolicyConfiguration", storePolicyConfiguration) // 数据存储策略配置
                .addConfigs(JSONObject.parseObject(configuration)); // 协议相关配置
    }

    /**
     * 转换协议支持配置
     * @param standby 协议支持配置
     * @return 转换后的协议支持配置
     */
    public static String toProtocolStandbyValue(String standby) {
        if (standby == null) {
            return "";
        }

        Map<String, JSONObject> standbyMap = JSON.parseObject(standby, (java.lang.reflect.Type)Map.class);

        if (standbyMap == null || standbyMap.isEmpty()) {
            return "";
        }

        ProtocolStandbyValue protocolStandbyValue = new ProtocolStandbyValue();

        standbyMap.forEach((thingId, expands) -> {

            String id = expands.getString("id");

            if (id == null) {
                return;
            }

            ProtocolStandbyValue.Cell cell = new ProtocolStandbyValue.Cell();
            cell.setThingId(thingId);
            cell.setId(id);
            cell.setExpands(expands);

            protocolStandbyValue.pushCell(cell);

        });

        return protocolStandbyValue.toJSONString();
    }
}
